import 'package:flutter/widgets.dart';
import 'package:lib_uikit/lib_uikit.dart';

/// @Title  page滚动翻页的Physics
/// @Author: bryce
/// @CreateDate: 2024年04月03日18:22:41
class GTPageScrollPhysics extends ScrollPhysics {
  final double cardWidth;

  /// 卡片间隔
  final double cardSpacing;

  /// 卡片左侧边距（用于计算卡片的起始位置，计算卡片滚动时中心点，）
  final double cardStartMargin;

  /// 卡片是否居中 (如果居中展示需要传入卡片左侧边距)
  final bool isCardCenter;

  /// Creates physics for a [PageView].
  const GTPageScrollPhysics(
      {super.parent,
      required this.cardWidth,
      required this.cardSpacing,
      this.cardStartMargin = 12,
      this.isCardCenter = true});

  double get cardPixels => cardWidth + cardSpacing;

  double get cardEndOffset => isCardCenter ? (GTScreen.width / 2 - cardWidth / 2 - cardStartMargin) : 0;

  @override
  GTPageScrollPhysics applyTo(ScrollPhysics? ancestor) {
    return GTPageScrollPhysics(
      parent: buildParent(ancestor),
      cardWidth: cardWidth,
      cardSpacing: cardSpacing,
      cardStartMargin: cardStartMargin,
      isCardCenter: isCardCenter,
    );
  }

  double _getPage(ScrollMetrics position) {
    if (position.pixels > cardStartMargin) {
      return (position.pixels + cardEndOffset) / cardPixels;
    }
    return position.pixels / cardPixels;
  }

  double _getPixels(ScrollMetrics position, double page) {
    return page * cardPixels - cardEndOffset;
  }

  double _getTargetPixels(ScrollMetrics position, Tolerance tolerance, double velocity) {
    double page = _getPage(position);
    if (velocity < -tolerance.velocity) {
      page -= 0.5;
    } else if (velocity > tolerance.velocity) {
      page += 0.5;
    }
    return _getPixels(position, page.roundToDouble());
  }

  @override
  Simulation? createBallisticSimulation(ScrollMetrics position, double velocity) {
    // If we're out of range and not headed back in range, defer to the parent
    // ballistics, which should put us back in range at a page boundary.
    if ((velocity <= 0.0 && position.pixels <= position.minScrollExtent) ||
        (velocity >= 0.0 && position.pixels >= position.maxScrollExtent)) {
      return super.createBallisticSimulation(position, velocity);
    }
    final Tolerance tolerance = toleranceFor(position);
    final double target = _getTargetPixels(position, tolerance, velocity);
    if (target != position.pixels) {
      return ScrollSpringSimulation(spring, position.pixels, target > 0 ? target : 0, velocity, tolerance: tolerance);
    }
    return null;
  }

  @override
  bool get allowImplicitScrolling => false;
}
